package task;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


public class Context implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Map<String, String> globals;
	private Map<String, Object> properties = new HashMap<String, Object>();
	private Map<String, String[]> taskValues = new HashMap<String, String[]>();
	public Map<String, String> getTaskProperties(ITask task) {
		Map<String, String> result = new TaskMap(task);
		return result;
	}
	public void setGlobals(Map<String, String> globals) {
		this.globals = globals;
	}
	public String[] getTaskValues(ITask task) {
		return taskValues.get(task.getSignature());
	}
	public void setTaskValues(ITask task, String[] v) {
		taskValues.put(task.getSignature(), v);
	}
	public Object getProperty(String key) {
		return properties.get(key);
	}
	public String getGlobal(String key) {
		String value = globals.get(key);
		return value;
	}
	public void setProperty(String key, Object value) {
		properties.put(key, value);
	}
	public void setTaskValue(ITask task, int rowNo, String value) {
		String[] tv = taskValues.get(task.getSignature());
		if (tv == null) {
			tv = new String[task.propertyNames().length];
			for (int i=0 ; i<tv.length ; i++) tv[i] = "";
			taskValues.put(task.getSignature(), tv);
		}
		int len = task.propertyNames().length;
		if (tv.length != len) {
			tv = new String[len];
			Arrays.fill(tv, "");
			taskValues.put(task.getSignature(), tv);
		}
		tv[rowNo] = value;
	}
	
	// TODO: check if these accessors needed by Jackson, need to be public
	public Map<String, Object> getProperties() {
		return properties;
	}
	public void setProperties(Map<String, Object> properties) {
		this.properties = properties;
	}
	public Map<String, String[]> getTaskValues() {
		return taskValues;
	}
	public void setTaskValues(Map<String, String[]> taskValues) {
		this.taskValues = taskValues;
	}
	public Map<String, String> getGlobals() {
		if (globals == null) {
			globals = new HashMap<String, String>();
		}
		return globals;
	}
	public class TaskMap implements Map<String, String> {

		private String[] taskVals;
		private String[] neededProps;

		public TaskMap(ITask task) {
			taskVals = taskValues.get(task.getSignature());
			if (taskVals == null) {
				taskVals = new String[task.propertyNames().length];
				taskValues.put(task.getSignature(), taskVals);
			}
			neededProps = task.propertyNames();
		}

		@Override
		public void clear() {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean containsKey(Object key) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean containsValue(Object value) {
			throw new UnsupportedOperationException();
		}

		@Override
		public Set<Entry<String, String>> entrySet() {
			throw new UnsupportedOperationException();
		}

		@Override
		public String get(Object key) {
			if (taskVals != null) {
				if (taskVals.length != neededProps.length) taskVals = null;
			}
			if (taskVals != null) {
				int i;
				for (i=0 ; i<neededProps.length ; i++) {
					if (key.equals(neededProps[i])) break;
				}
				if (i<taskVals.length) {
					if (taskVals[i] != null && !"".equals(taskVals[i])) {
						return taskVals[i];
					}
				}
			}
			if (globals != null) {
				String value = globals.get(key);
				if (value != null) return value;
			}
			return null;
		}

		@Override
		public boolean isEmpty() {
			throw new UnsupportedOperationException();
		}

		@Override
		public Set<String> keySet() {
			throw new UnsupportedOperationException();
		}

		@Override
		public String put(String key, String value) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void putAll(Map<? extends String, ? extends String> m) {
			throw new UnsupportedOperationException();
		}

		@Override
		public String remove(Object key) {
			throw new UnsupportedOperationException();
		}

		@Override
		public int size() {
			throw new UnsupportedOperationException();
		}

		@Override
		public Collection<String> values() {
			throw new UnsupportedOperationException();
		}
	}

}
